package com.maoye.ossp.bpm.bpmweb.utils;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.maoye.ossp.bpm.bpmweb.controller.executor.BpmxExecutor;

/**
 * 内存数据收集缓存对象，与{@link BpmxExecutor 执行器}关联可自动触发执行
 * 
 * @author hedh
 * 
 */
public class DataHolder {

	/**
	 * 流程变量
	 */
	public static final String KEY_VARS = "data_vars";

	/**
	 * 表单数据
	 */
	public static final String KEY_FORM = "data_form";

	/**
	 * 流程节点信息
	 */
	public static final String KEY_NODE = "data_node";

	private Set<String> keys;

	private Map<String, Object> _cache;

	private Map<String, Object> params = new HashMap<String, Object>();

	private boolean hasError = false;

	/**
	 * 具体执行对象
	 */
	private BpmxExecutor excutor;

	/**
	 * 创建数据缓存对象，并设置数据类别
	 * 
	 * @param keys
	 */
	public DataHolder(String... keys) {
		if (keys.length == 0) {
			throw new RuntimeException("无效代码");
		}
		this.keys = new HashSet<String>();
		_cache = new HashMap<String, Object>();
		for (String key : keys) {
			_cache.put(key, null);
			this.keys.add(key);
		}
	}

	/**
	 * 移除
	 * 
	 * @param key
	 */
	public void remove(String key) {
		keys.remove(key);
		_cache.remove(key);
	}

	/**
	 * 检查预定义类别是否已全部装载数据
	 * 
	 * @return
	 */
	public boolean finished() {
		for (String key : keys) {
			if (_cache.get(key) == null) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 获取缓存数据
	 * 
	 * @param key
	 * @return
	 */
	public Object getData(String key) {
		if (!check(key)) {
			throw new RuntimeException("索引值不在初始化队列中");
		}
		return _cache.get(key);
	}

	/**
	 * <pre>
	 * 此方法建议在所有设置类方法中最后执行。设置缓存数据并检查，当预定义类别数据收集完成并设置了{@link BpmxExecutor 执行器}，则触发执行对象执行操作。
	 * 如果没有设置{@link BpmxExecutor 执行器}，可自行检查数据状态{@link DataHolder#finished() finished}， 并创建执行对象：
	 * 	DataHolder holder = new DataHolder(key1,key2);
	 * 	holder.setData(key1,"缓存数据");
	 * 	holder.setData(key2,"缓存数据");
	 * 	if(holder.finished()){
	 * 		BpmxExecutor executor = ...;
	 * 		String result = executor.execute(holder);
	 * 		// 处理返回数据
	 * 	}
	 * </pre>
	 * 
	 * @param key
	 * @param data
	 * @return
	 */
	public String setData(String key, Object data) {
		if (!check(key)) {
			throw new RuntimeException("索引值不在初始化队列中");
		}
		_cache.put(key, data);
		if (finished() && hasExecutor()) {
			return execute();
		}
		return null;
	}

	/**
	 * 检查是否为预定义类别
	 * 
	 * @param key
	 * @return
	 */
	private boolean check(String key) {
		for (String k : keys) {
			if (k.equals(key)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 获取上下文中的参数
	 * 
	 * @param key
	 * @param value
	 */
	public void setParameter(String key, Object value) {
		params.put(key, value);
	}

	/**
	 * 上下文中设置参数
	 * 
	 * @param key
	 * @return
	 */
	public Object getParameter(String key) {
		return params.get(key);
	}

	public void clear() {
		keys = null;
		excutor = null;
		_cache.clear();
		params.clear();
	}

	/**
	 * 设置具体执行对象
	 * 
	 * @param excutor
	 * @return
	 */
	public DataHolder setExcutor(BpmxExecutor excutor) {
		this.excutor = excutor;
		return this;
	}

	public boolean hasExecutor() {
		return this.excutor != null;
	}

	/**
	 * 调用执行对象
	 * 
	 * @return
	 */
	public String execute() {
		if (hasExecutor()) {
			return this.excutor.execute(this);
		}
		return null;
	}

	/**
	 * 标记发生异常
	 */
	public void markError() {
		this.hasError = true;
	}

	/**
	 * 是否发生异常
	 * 
	 * @return
	 */
	public boolean hasError() {
		return this.hasError;
	}
}
